#pragma once

#include <gst/gst.h>
#define GST_USE_UNSTABLE_API
#include <gst/webrtc/webrtc.h>
#include <memory>
#include <map>
#include <mutex>
#include <thread>
#include "common_media_define.h"
#include "media_stream.h"
#include "web_server.h"
#include "base_time_cost.h"

namespace El {
namespace StreamServer {

struct MediaData {
    GstElement *appsrc_video;
    GstElement *appsrc_audio;
    uint32_t channel;
    uint32_t stream_type;
    int stream_handle;
    Media::StreamSourcePtr streamSource;
};
using MediaDataPtr = std::shared_ptr<MediaData>;

struct ClientConnection {
    void *ws_conn;
    GstElement *pipeline;
    GstElement *webrtc_element;
    MediaDataPtr media_data;
    Base::TimeCost time_cost;

    ClientConnection() : ws_conn(nullptr), pipeline(nullptr), webrtc_element(nullptr) {}
};

class StreamGstWebRTC {
public:
    static StreamGstWebRTC &GetInstance();

    bool Start();

    void Stop();

private:
    StreamGstWebRTC();
    ~StreamGstWebRTC();

    // 禁止拷贝和赋值
    StreamGstWebRTC(const StreamGstWebRTC &) = delete;
    StreamGstWebRTC &operator=(const StreamGstWebRTC &) = delete;

    void SetupNewPeerConnection();
    void CleanupPeerConnection();
    void PushFrame(const Media::MediaFramePtr &frame, MediaDataPtr stream);
    void SendSdpToPeer(GstWebRTCSessionDescription *desc, void *connection);
    void SendIceCandidateToPeer(guint mlineindex, gchar *candidate, void *connection);
    void OnOfferCreated(GstPromise *promise, GstElement *webrtc, ClientConnection *client);
    void OnNegotiationNeeded(GstElement *webrtc, ClientConnection *client);
    void OnIceCandidate([[maybe_unused]] GstElement *webrtc,
                        guint mlineindex,
                        gchar *candidate,
                        ClientConnection *client);
    void SetupPipelineForClient(std::shared_ptr<ClientConnection> client_conn);
    void CleanupClientConnection(std::shared_ptr<ClientConnection> client);
    void HandleWebSocketEvent(std::shared_ptr<El::WebServer::WebSocketEvent> &event);
    void HandleWebSocketMessage(std::shared_ptr<ClientConnection> client, const std::string &message);
    void SendWebSocketTextMessage(void *connection, const std::string &message);

private:
    GstElement *pipeline_;
    bool running_;
    bool audio_enable_;
    std::thread ws_thread_;
    std::map<void *, std::shared_ptr<ClientConnection>> connections_;
    std::mutex connections_mutex_;
};

} // namespace StreamServer
} // namespace El